package com.xjc.business.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alipay.api.internal.util.AlipaySignature;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xjc.business.entity.domain.*;
import com.xjc.business.entity.po.schadmin.ActiveSchoolPo;
import com.xjc.business.entity.vo.SetVo2;
import com.xjc.business.entity.vo.SetVo3;
import com.xjc.business.service.*;
import com.xjc.business.mapper.SchoolSetsMapper;
import com.xjc.system.constants.MyConstants;
import com.xjc.system.properties.AlipayProperties;
import com.xjc.system.result.Result;
import com.xjc.system.utils.AlipayUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
* @author root
* @description 针对表【school_sets(学校套餐信息)】的数据库操作Service实现
* @createDate 2025-01-25 10:24:32
*/
@Service
public class SchoolSetsServiceImpl extends ServiceImpl<SchoolSetsMapper, SchoolSets>
    implements SchoolSetsService {

    @Autowired
    @Lazy
    SetsService setsService;

    @Autowired
    AlipayUtil alipayUtil;

    @Autowired
    AlipayProperties alipayProperties;

    @Autowired
    RedisTemplate<String,Object> redisTemplate;

    @Autowired
    @Lazy
    SchoolAdminRelationsService schoolAdminRelationsService;

    @Autowired
    @Lazy
    CollageAdminRelationsService collageAdminRelationsService;

    @Autowired
    @Lazy
    SchoolCollegeRelationsService schoolCollegeRelationsService;

    @Autowired
    @Lazy
    CollageClazzAdminRelationsService collageClazzAdminRelationsService;

    @Autowired
    @Lazy
    AllStudentRegsiterRelationsService allStudentRegsiterRelationsService;

    @Autowired
    @Lazy
    SchoolDoorAdminRelationsService schoolDoorAdminRelationsService;

    @Autowired
    @Lazy
    SchoolBuildingAdminRelationsService schoolBuildingAdminRelationsService;

    @Autowired
    @Lazy
    WxUserService wxUserService;

    /**
     * 开通服务
     *
     * @param activeSchoolPo 学校和套餐信息
     * @return 反馈
     * TODO 接入支付宝沙盒支付
     */
    @Override
    public Result<String> activeSchool(ActiveSchoolPo activeSchoolPo) {
        Integer schoolId = activeSchoolPo.schoolId;
        Integer setId = activeSchoolPo.setId;

        // 保存预订单信息
        SchoolSets schoolSets = new SchoolSets();
        schoolSets.setSetId(setId);
        schoolSets.setSchId(schoolId);
        schoolSets.setPayStatus(MyConstants.SET_NOT_PAY);
        schoolSets.setCreateTime(new Date());
        schoolSets.setUpateTime(new Date());
        save(schoolSets);

        Sets sets = setsService.getById(setId);

        // 生成支付页面
        String order = alipayUtil.createOrder(MyConstants.PREFIX_TRADE_NO + schoolSets.getId(),"付费套餐："+ sets.getSetName(), String.valueOf(sets.getMoney()));

        return Result.okWithData(order);
    }

    /**
     * 查询套餐信息
     * @param id 学校id
     * @return 信息
     */
    @Override
    public Result<SetVo2> getSetInfo(Integer id) {

        LambdaQueryWrapper<SchoolSets> schoolSetsLambdaQueryWrapper = new LambdaQueryWrapper<>();
        schoolSetsLambdaQueryWrapper.eq(SchoolSets::getSchId,id);
        SetVo2 setPo = new SetVo2();
        if(count(schoolSetsLambdaQueryWrapper) > 0){
            SchoolSets schoolSets = getOne(schoolSetsLambdaQueryWrapper);
            Integer setId = schoolSets.getSetId();
            Sets sets = setsService.getById(setId);

            setPo.setId(sets.getId());
            setPo.setDuration(sets.getDuration());
            setPo.setMoney(sets.getMoney());
            setPo.setSetName(sets.getSetName());
            setPo.setSetBeginTime(schoolSets.getSetBeginTime());
            setPo.setSetEndTime(schoolSets.getSetEndTime());
            return Result.okWithData(setPo);

        }
        return Result.okWithData(null);

    }

    /**
     * 获取套餐历史开通信息
     * @param id 学校id
     * @return 信息
     */
    @Override
    public Result<List<SetVo3>> getSchoolSetsHistoryList(Integer id) {
        LambdaQueryWrapper<SchoolSets> schoolSetsLambdaQueryWrapper = new LambdaQueryWrapper<>();
        schoolSetsLambdaQueryWrapper.eq(SchoolSets::getSchId,id);

        List<SetVo3> vo3List = list(schoolSetsLambdaQueryWrapper).stream().map(item -> {
            SetVo3 setVo = new SetVo3();
            setVo.setId(item.getId());
            Sets sets = setsService.getById(item.getSetId());
            setVo.setDuration(sets.getDuration());
            setVo.setSetName(sets.getSetName());
            setVo.setMoney(sets.getMoney());
            setVo.setPayStatus(item.getPayStatus());
            setVo.setSetBeginTime(item.getSetBeginTime());
            setVo.setSetEndTime(item.getSetEndTime());
            setVo.setCreateTime(item.getCreateTime());
            setVo.setSetId(item.getSetId());

            return setVo;
        }).collect(Collectors.toList());

        return Result.okWithData(vo3List);
    }

    /**
     * 异步支付结果反馈
     * @param response
     * @return success or failure
     */
    @Override
    public void notifyBack(HttpServletRequest request, HttpServletResponse response) {
       try {

           Map<String,String> params = new HashMap<String,String>();
           Map<String,String[]> requestParams = request.getParameterMap();
           for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
               String name = (String) iter.next();
               String[] values = (String[]) requestParams.get(name);
               String valueStr = "";
               for (int i = 0; i < values.length; i++) {
                   valueStr = (i == values.length - 1) ? valueStr + values[i]
                           : valueStr + values[i] + ",";
               }
               //乱码解决，这段代码在出现乱码时使用
               valueStr = new String(valueStr.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
               params.put(name, valueStr);
           }
           System.out.println("异步");

           boolean signVerified = AlipaySignature.rsaCheckV1(params,alipayProperties.getAlipayPublicKey(), "utf-8", "RSA2"); //调用SDK验证签名
           if(signVerified){
               // 继续业务处理
               //交易状态
               String trade_status = new String(request.getParameter("trade_status").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);

               if(trade_status.equals("TRADE_SUCCESS")){
                   //支付成功
                   //商户订单号
                   String out_trade_no = new String(request.getParameter("out_trade_no").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
                   payAfterUpdateOrder(out_trade_no);
               }

               // 验签成功在response中返回success
               response.getWriter().print("success");
           }else{
               // 验签失败在response中返回failure
               response.getWriter().print("fail");
           }

       }catch (Exception e){
           e.printStackTrace();
           try {
               response.getWriter().print("fail");
           } catch (IOException ex) {
               throw new RuntimeException(ex);
           }

       }
    }

    /**
     * 同步支付结果反馈
     */
    @Override
    public String returnBack(HttpServletRequest request) {
        try {

            Map<String,String> params = new HashMap<String,String>();
            Map<String,String[]> requestParams = request.getParameterMap();
            for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
                String name = (String) iter.next();
                String[] values = (String[]) requestParams.get(name);
                String valueStr = "";
                for (int i = 0; i < values.length; i++) {
                    valueStr = (i == values.length - 1) ? valueStr + values[i]
                            : valueStr + values[i] + ",";
                }
                //乱码解决，这段代码在出现乱码时使用
                valueStr = new String(valueStr.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
                params.put(name, valueStr);
            }
            System.out.println("同步");

            boolean signVerified = AlipaySignature.rsaCheckV1(params,alipayProperties.getAlipayPublicKey(), "utf-8", "RSA2"); //调用SDK验证签名
            if(signVerified){
                // 继续业务处理
                // 商户订单号
                String out_trade_no = new String(request.getParameter("out_trade_no").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
                return payAfterUpdateOrder2(out_trade_no);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return "支付失败，稍后重试";

    }

    /**
     * 获取未支付订单
     * @param id 学校id
     * @return 订单id
     */
    @Override
    public Result<Integer> queryNotPayOrder(Integer id) {
        LambdaQueryWrapper<SchoolSets> schoolSetsLambdaQueryWrapper = new LambdaQueryWrapper<>();
        schoolSetsLambdaQueryWrapper.eq(SchoolSets::getSchId,id);
        schoolSetsLambdaQueryWrapper.eq(SchoolSets::getPayStatus,MyConstants.SET_NOT_PAY);
        SchoolSets schoolSets = getOne(schoolSetsLambdaQueryWrapper);
        if(schoolSets != null){
            return Result.okWithData(schoolSets.getId());
        }
        return Result.ok();
    }

    /**
     * 删除未支付订单
     * @param id 订单id
     * @return 反馈
     */
    @Override
    public Result<String> deleteNotPayOrder(Integer id) {
        removeById(id);
        return Result.okWithData("删除成功");
    }

    /**
     * 继续支付
     * @param id 订单id
     * @return 反馈
     */
    @Override
    public String continuePay(Integer id) {
        return payAfterUpdateOrder2(MyConstants.PREFIX_TRADE_NO+id);
    }

    /**
     * 确认所属学校是否开通套餐
     * @param role 角色类型
     * @param id id
     * @return 反馈
     */
    @Override
    public boolean sureHasSet(String role, Integer id) {
        Integer schoolId = null;
        switch (role){
            case MyConstants.SCHOOL_ROLE:
                LambdaQueryWrapper<SchoolAdminRelations> schoolAdminRelationsLambdaQueryWrapper = new LambdaQueryWrapper<>();
                schoolAdminRelationsLambdaQueryWrapper.eq(SchoolAdminRelations::getSchAdminId, id);
                schoolId = schoolAdminRelationsService.getOne(schoolAdminRelationsLambdaQueryWrapper).getSchId();
                break;
            case MyConstants.COLLEGE_ROLE:
                LambdaQueryWrapper<CollageAdminRelations> collageAdminRelationsLambdaQueryWrapper = new LambdaQueryWrapper<>();
                collageAdminRelationsLambdaQueryWrapper.eq(CollageAdminRelations::getColAdminId, id);
                CollageAdminRelations collageAdminRelations = collageAdminRelationsService.getOne(collageAdminRelationsLambdaQueryWrapper);
                LambdaQueryWrapper<SchoolCollegeRelations> schoolCollegeRelationsLambdaQueryWrapper = new LambdaQueryWrapper<>();
                schoolCollegeRelationsLambdaQueryWrapper.eq(SchoolCollegeRelations::getColId, collageAdminRelations.getColId());
                schoolId = schoolCollegeRelationsService.getOne(schoolCollegeRelationsLambdaQueryWrapper).getSchId();
                break;
            case MyConstants.CLASS_ROLE:
                LambdaQueryWrapper<CollageClazzAdminRelations> collageClazzAdminRelationsLambdaQueryWrapper = new LambdaQueryWrapper<>();
                collageClazzAdminRelationsLambdaQueryWrapper.eq(CollageClazzAdminRelations::getClazzAdminId, id);
                CollageClazzAdminRelations collageClazzAdminRelations = collageClazzAdminRelationsService.getOne(collageClazzAdminRelationsLambdaQueryWrapper);

                LambdaQueryWrapper<SchoolCollegeRelations> schoolCollegeRelationsLambdaQueryWrapper2 = new LambdaQueryWrapper<>();
                schoolCollegeRelationsLambdaQueryWrapper2.eq(SchoolCollegeRelations::getColId, collageClazzAdminRelations.getColId());
                schoolId = schoolCollegeRelationsService.getOne(schoolCollegeRelationsLambdaQueryWrapper2).getSchId();
                break;
            case MyConstants.STU_ROLE_LOGIN:

                LambdaQueryWrapper<AllStudentRegsiterRelations> allStudentRegsiterRelationsLambdaQueryWrapper = new LambdaQueryWrapper<>();
                allStudentRegsiterRelationsLambdaQueryWrapper.eq(AllStudentRegsiterRelations::getStuId, id);
                AllStudentRegsiterRelations allStudentRegsiterRelations = allStudentRegsiterRelationsService.getOne(allStudentRegsiterRelationsLambdaQueryWrapper);

                schoolId =allStudentRegsiterRelations!=null?allStudentRegsiterRelations.getSchId():null;
                break;
            case MyConstants.STU_ROLE:
                Integer stuId = wxUserService.getById(id).getStuId();
                if(stuId == null){
                    return true;

                }
                else{
                    LambdaQueryWrapper<AllStudentRegsiterRelations> allStudentRegsiterRelationsLambdaQueryWrapper2 = new LambdaQueryWrapper<>();
                    allStudentRegsiterRelationsLambdaQueryWrapper2.eq(AllStudentRegsiterRelations::getStuId, stuId);
                    AllStudentRegsiterRelations allStudentRegsiterRelations2 = allStudentRegsiterRelationsService.getOne(allStudentRegsiterRelationsLambdaQueryWrapper2);

                    schoolId =allStudentRegsiterRelations2!=null?allStudentRegsiterRelations2.getSchId():null;
                }
                break;
            case MyConstants.DOOR_ROLE:
                LambdaQueryWrapper<SchoolDoorAdminRelations> schoolDoorAdminRelationsLambdaQueryWrapper = new LambdaQueryWrapper<>();
                schoolDoorAdminRelationsLambdaQueryWrapper.eq(SchoolDoorAdminRelations::getDoorAdminId, id);
                schoolId = schoolDoorAdminRelationsService.getOne(schoolDoorAdminRelationsLambdaQueryWrapper).getSchId();
                break;
            case MyConstants.BUILD_ROLE:
                LambdaQueryWrapper<SchoolBuildingAdminRelations> schoolBuildingAdminRelationsLambdaQueryWrapper = new LambdaQueryWrapper<>();
                schoolBuildingAdminRelationsLambdaQueryWrapper.eq(SchoolBuildingAdminRelations::getBuildAdminId, id);
                schoolId = schoolBuildingAdminRelationsService.getOne(schoolBuildingAdminRelationsLambdaQueryWrapper).getSchId();
                break;
            default:
                return false;
        }

        return redisTemplate.opsForValue().get(MyConstants.PREFIX_SET_TOKEN + schoolId) != null;
    }

    @Async
    public void payAfterUpdateOrder(String tradeNo){
        extractedUpdateOrder(tradeNo);
    }

    public String payAfterUpdateOrder2(String tradeNo){
        extractedUpdateOrder(tradeNo);

        return
                "<!DOCTYPE html>\n" +
                "<html>\n" +
                "<head>\n" +
                "    <script type=\"text/javascript\">\n" +
                "        window.onload = function() {\n" +
                "            window.close();\n" +
                "        };\n" +
                "    </script>\n" +
                "</head>\n" +
                "<body>\n" +
                "</body>\n" +
                "</html>";
    }

    private void extractedUpdateOrder(String tradeNo) {
        Integer schoolSetId = Integer.valueOf(tradeNo.split(MyConstants.PREFIX_TRADE_NO)[1]);
        SchoolSets schoolSets = getById(schoolSetId);
        if (schoolSets!=null &&  !Objects.equals(schoolSets.getPayStatus(), MyConstants.SET_HAS_PAY)) {
            Integer setId = schoolSets.getSetId();
            Sets sets = setsService.getById(setId);
            Integer duration = sets.getDuration();
            schoolSets.setPayStatus(MyConstants.SET_HAS_PAY);
            LocalDateTime currentDate = LocalDateTime.now();

            schoolSets.setSetBeginTime(Date.from(currentDate.atZone(ZoneId.systemDefault()).toInstant()));
            schoolSets.setSetEndTime(Date.from(currentDate.plusDays(duration).atZone(ZoneId.systemDefault()).toInstant()));

            updateById(schoolSets);

            // 保存学校开通套餐记录到redis，过期时间为duration天后
            redisTemplate.opsForValue().set(MyConstants.PREFIX_SET_TOKEN+schoolSets.getSchId(), JSONArray.toJSONString(true),duration, TimeUnit.DAYS);
        }
    }
}